package mainserver

import (
	"bytes"

	"encoding/json"

	"gcc/global"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"

	"image"
	"io/ioutil"
	"log"
	"net/http"

	"gocv.io/x/gocv"
)

// 初始化界面
func InitWin(videoPath interface{}) {
	a := app.New()
	win := a.NewWindow("video show")
	win.Resize(fyne.Size{300, 300})
	detectChan := make(chan gocv.Mat)
	showChan := make(chan image.Image)
	flagChan := make(chan bool)
	name2url, err := getServiceUrl()
	if err != nil {
		log.Printf("getServiceUrl() failed ,please checkout mainserver/mainServer.go \n")
		return
	}
	go getPic(detectChan, showChan, flagChan, videoPath)
	go getServer(detectChan, flagChan, name2url)
	go changeWinContent(win, showChan)
	win.ShowAndRun()
}

// 获取服务地址
func getServiceUrl() (map[global.ServiceName]global.Address, error) {
	resp, err := http.Get("http://"+string(global.RegistryAddress) + "/getservices?servicename=" + string(global.PeopleDetectService))

	if err != nil {
		log.Printf("mainserver/mainServer.go: http.get() failed \n")
		return nil, err
	}
	defer resp.Body.Close()
	var name2url map[global.ServiceName]global.Address
	if err != nil {
		log.Printf("mainserver/mainServer.go: ioutil.Readall() failed \n")
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(body, &name2url)
	if err != nil {
		log.Printf("mainserver/mainServer.go: json.Unmarshal() failed \n")
		return nil, err
	}
	return name2url, nil
}

// 这个方法要获取图片，
func getPic(d chan gocv.Mat, s chan image.Image, showFlag chan bool, videoPath interface{}) {
	cap, err := gocv.OpenVideoCapture(videoPath)
	if err != nil {
		log.Printf("open carmera failed, please check peopleDetectService/server.go, err: %s \n", err.Error())
		return
	}
	defer cap.Close()
	var mat gocv.Mat
	count := 0
	flag := false
	for cap.IsOpened() {
		b := cap.Read(&mat)
		count++
		if b {
			if count%10 == 0 {
				d <- mat
				count = 0
			}
			select {
			case flag = <-showFlag:

			default:
				if flag {
					showImage, err := cvMat2Image(mat, gocv.JPEGFileExt)
					if err != nil {
						log.Printf("cvMat2Image failed,please check mainserver/mainServer.go \n")
					}
					s <- showImage
				}
			}

		}
	}
}

// 进行服务获取
func getServer(d chan gocv.Mat, f chan bool, name2url map[global.ServiceName]global.Address) {
	url := name2url[global.PeopleDetectService]
	for {
		mat := <-d
		buf, err := gocv.IMEncode(gocv.JPEGFileExt, mat)
		if err != nil {
			log.Printf("gocv.IMEncode() failed, please check out mainserver/mainServer.go")
			return
		}
		reader := bytes.NewReader(buf.GetBytes())
		resp, err := http.Post(string(url)+"/predict", "image/jpeg", reader)
		if err != nil {
			log.Printf("http.post failed; please checkout mainserver/mainServer.go, err: %s \n", err.Error())
			return
		}
		defer resp.Body.Close()
		if err != nil {
			log.Printf("http.POST() failed, please check out mainserver/mainServer.go")
			return
		}
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Printf("ioutil.Readall() failed, please check out mainserver/mainServer.go")
			return
		}
		var res map[string]bool
		err = json.Unmarshal(body, &res)
		if err != nil {
			log.Printf("json.unMarshal failed, please check out mainserver/mainServer.go")
			return
		}
		if isPeople, ok := res["data"]; ok && isPeople {
			f <- true
		}
	}
}

// 对画面的显示
func changeWinContent(window fyne.Window, imageChan <-chan image.Image) {
	for {
		img := <-imageChan
		content := canvas.NewImageFromImage(img)
		window.SetContent(content)
	}

}

// 将opencv的mat格式的图片转换成golang的image类型。
func cvMat2Image(mat gocv.Mat, format gocv.FileExt) (image.Image, error) {
	buf, err := gocv.IMEncode(format, mat)
	if err != nil {
		return nil, err
	}
	reader := bytes.NewReader(buf.GetBytes())
	destImage, _, err := image.Decode(reader)
	if err != nil {
		return nil, err
	}
	return destImage, nil
}
